package woniusinffer;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;


import jpcap.*;
import com.woniu.utils.system.WSystem;

public class ArpPacketCapture implements JpcapHandler, Runnable {

    static {
        WSystem.addDir("lib");
    }
    private String deviceName;
    private CaptureUI ui;
    private boolean isHz = true;//混杂模式标志
    //private ArrayList<String> packageMessage=new ArrayList<String>();
    private Jpcap jpcap = null;
    private boolean canService = true;
    private static long packets = 0;

    @SuppressWarnings("deprecation")
    @Override
    public void handlePacket(Packet packet) {
        if (isCanService()) {
//            System.out.println(packet instanceof TCPPacket && ui.tcpchk.isSelected());
//this is a test two
            if (packet instanceof TCPPacket && ui.tcpchk.isSelected()) {
                TCPPacket ipp = (TCPPacket) packet;
                String data = getData(ipp); 
                String str = "\n-->" + ipp.src_ip + "->" + ipp.dst_ip + "\nContent:\n"
                        + data 
                        + "\n" + packet.toString() + "\n";
                show(ipp, str);
            }
            if (packet instanceof UDPPacket && ui.udpchk.isSelected()) {
                UDPPacket ipp = (UDPPacket) packet;
                String data = getData(ipp); 
                String str = "\n-->" + ipp.src_ip + "->" + ipp.dst_ip + "\nContent:\n"
                        + data 
                        + "\n" + packet.toString() + "\n";
                show(ipp, str);
            }
            if (packet instanceof ICMPPacket && ui.icmpchk.isSelected()) {
                ICMPPacket ipp = (ICMPPacket) packet;
                String data = getData(ipp); 
                String str = "\n-->" + ipp.src_ip + "->" + ipp.dst_ip + "\nContent:\n"
                        + data 
                        + "\n" + packet.toString() + "\n";
                show(ipp, str);
            }
            if (packet instanceof ARPPacket && ui.arpchk.isSelected()) {
                ARPPacket ipp = ((ARPPacket) packet);
                String str =
                        "\n==========================" + getOptionType(ipp.operation) + "(" + (++packets) + ")" + "=============================="
                        + "\n物理网络类型　----->　" + ipp.hardtype
                        + "\n协议类型　　　----->　" + ipp.prototype
                        + "\n物理地址长度　----->　" + ipp.hlen
                        + "\n协议地址长度　----->　" + ipp.plen
                        + "\n操作　　　　　----->　" + ipp.operation + "　(" + getOptionType(ipp.operation) + ")"
                        + "\n源物理地址　　----->　" + ipp.getSenderHardwareAddress()
                        + "\n源IP地址　　　----->　" + ipp.getSenderProtocolAddress()
                        + "\n目的物理地址　----->　" + ipp.getTargetHardwareAddress()
                        + "\n目的IP地址　　----->　" + ipp.getTargetProtocolAddress()
                        + "\n时间　　　　　----->　" + new Date(ipp.sec * 1000).toLocaleString();
                show(ipp, str);
            }


        }

    }

    public void show(IPPacket ipp, String str) {

        if (!ui.containsjField.getText().isEmpty() && !ui.contentJTextField.getText().isEmpty()) {
            if ((ipp.src_ip.getHostAddress().indexOf(ui.containsjField.getText()) != -1
                    || ipp.dst_ip.getHostAddress().indexOf(ui.containsjField.getText()) != -1)
                    && new String(ipp.data).toLowerCase().indexOf(ui.contentJTextField.getText().toLowerCase()) != -1) {
                show2(ipp, str);
            }
        } else if (!ui.contentJTextField.getText().isEmpty()) {
            try {
                String string = ui.charsetJTextField.getText().isEmpty() ? new String(ipp.data) : new String(ipp.data, ui.charsetJTextField.getText());
                if (string.toLowerCase().indexOf(ui.contentJTextField.getText().toLowerCase()) != -1) {
                    show2(ipp, str);
                }
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(ArpPacketCapture.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else if (!ui.containsjField.getText().isEmpty()) {
            if (ipp.src_ip.getHostAddress().indexOf(ui.containsjField.getText()) != -1
                    || ipp.dst_ip.getHostAddress().indexOf(ui.containsjField.getText()) != -1) {
                show2(ipp, str);
            }
        } else {
            show2(ipp, str);
        }
    }

    private void show2(IPPacket ipp, String str) {

        if (!ui.from.getText().isEmpty() && !ui.to.getText().isEmpty()) {
            if (ipp.src_ip.getHostAddress().equals(ui.from.getText()) && ipp.dst_ip.getHostAddress().equals(ui.to.getText())) {
                ui.addMessage(str);
            }
        } else if (!ui.from.getText().isEmpty()) {
            if (ipp.src_ip.getHostAddress().equals(ui.from.getText())) {
                ui.addMessage(str);
            }
        } else if (!ui.to.getText().isEmpty()) {
            if (ipp.dst_ip.getHostAddress().equals(ui.to.getText())) {
                ui.addMessage(str);
            }
        } else {
            ui.addMessage(str);
        }
    }

    private String getData(IPPacket ipp) {
        String data = new String(ipp.data);
        try {
            data = ui.charsetJTextField.getText().isEmpty() ? data : new String(ipp.data, ui.charsetJTextField.getText());
        } catch (UnsupportedEncodingException ex) {
        }
        return data;
    }

    public void show(ARPPacket ipp, String str) {

        if (!ui.from.getText().isEmpty() && !ui.to.getText().isEmpty()) {
            if (ipp.getSenderProtocolAddress().equals(ui.from.getText()) && ipp.getTargetProtocolAddress().equals(ui.to.getText())) {
                ui.addMessage(str);
            }
        } else if (!ui.from.getText().isEmpty()) {
            if (ipp.getSenderProtocolAddress().equals(ui.from.getText())) {
                ui.addMessage(str);
            }
        } else if (!ui.to.getText().isEmpty()) {
            if (ipp.getSenderProtocolAddress().equals(ui.to.getText())) {
                ui.addMessage(str);
            }
        } else {
            ui.addMessage(str);
        }
    }

    public String getOptionType(long type) {
        HashMap<Long, String> types = new HashMap<Long, String>();
        types.put(1l, "ARP请求报文");
        types.put(2l, "ARP应答报文");
        types.put(3l, "RARP请求报文");
        types.put(4l, "RARP应答报文");
        if (types.containsKey(type)) {
            return types.get(type);
        } else {
            return "无法识别";
        }
    }

    @Override
    public void run() {
        try {
            jpcap = Jpcap.openDevice(getDeviceName(), 65525, isHz(), 100);
            //deviceName即将打开的设备名//
            //1028从设备上一次读取的最大字节数//
            //true说明是否将设备设为混杂模式的Boolean值//
            //100超时值//
            jpcap.loopPacket(-1, this);
        } catch (IOException e) {
            ui.addMessage("\n打开网卡出错。错误信息:" + e.getMessage());
        }

    }

    public static void log(String info) {
        try {
            FileOutputStream fos = new FileOutputStream(new File("log.txt"), true);
            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
            osw.append(info);
            osw.flush();
            osw.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static String[] getNetInterfaceList() {
        String[] devices = Jpcap.getDeviceList();
        return devices;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }

    public CaptureUI getUi() {
        return ui;
    }

    public void setUi(CaptureUI ui) {
        this.ui = ui;
    }

    public boolean isHz() {
        return isHz;
    }

    public void setHz(boolean isHz) {
        this.isHz = isHz;
    }

    public boolean isCanService() {
        return canService;
    }

    public void setCanService(boolean canService) {
        this.canService = canService;
    }
}
